#include "StdAfx.h"
#include "TPAuthCenter.h"
#include "TPTrack.h"
#include "Rijndael.h"
#include "TPTools.h"
#include "TPDefine.h"
#include "MAPICenter.h"
#include "TPAuthDlg.h"
#include <fstream>


LPCTSTR	lpszAuthFile	= _T("Auth.bin");
LPCSTR	lpKey			= "TimeKeyMakeIs_OK";
LPCSTR	lpChain			= "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0";

CTPAuthCenter::CTPAuthCenter(void)
		: m_pCrypt(NULL),
		m_pAuthDlg(NULL)
{
	m_pCrypt = new CRijndael;
	m_pCrypt->MakeKey(lpKey, lpChain);

	Load();

	CMAPICenter::AdviseSink(CTPAuthCenter::AdviseSinkCallback);

	m_pAuthDlg = new CTPAuthDlg;
}

CTPAuthCenter::~CTPAuthCenter(void)
{
	Save();

	delete m_pAuthDlg;
	delete m_pCrypt;
}

CTPAuthCenter* CTPAuthCenter::Instance()
{
	static Smart_ptr::SmartPtr<CTPAuthCenter> pAuthCenter;

	if ( NULL == pAuthCenter )
	{
		pAuthCenter = new CTPAuthCenter();
	}

	return pAuthCenter;
}

BOOL CTPAuthCenter::GetAuthorize(LPCTSTR lpstrTitle, LPCTSTR lpszCode)
{
	BOOL bResult = FALSE;

	CTPAuthCenter*	pCenter	= Instance();
	CKeyAuthIter	iter	= pCenter->m_Authorizations.find(lpstrTitle);

	if ( pCenter->m_Authorizations.end() != iter )
	{
		CKeyAuthPtr pAuth = (*iter).second;

		if ( 0 < pAuth->dwCount )
		{
			if ( !pAuth->bOpen )
			{
				--(pAuth->dwCount);
				pAuth->bOpen = TRUE;
			}
			bResult = TRUE;
		}
		else
		{
			pCenter->m_Authorizations.erase(iter);
		}
	}

	if ( !bResult )
	{
		CString strQuery;
		strQuery.LoadString(IDS_QUERY_SEND);

		if ( IDYES == ::MessageBox(NULL, strQuery, _T(""), MB_YESNO) )
		{
			if ( TPTools::SendSMSMessage(lpszCode, lpstrTitle) )
			{
				CKeyAuthPtr pAuth	= new KEYAUTH;
				pAuth->dwCount		= 2;
				pAuth->strKey		= lpstrTitle;
				pAuth->strCode		= lpszCode;

				pCenter->m_Authorizations.insert(CKeyAuths::value_type(pAuth->strKey, pAuth));
				//bResult = (-1 == pCenter->m_pAuthDlg->DoModal());
				bResult = TRUE;
			}
			else
			{
				DWORD dwError = ::GetLastError();
				CString strError;
				strError.Format(_T("%d"), dwError);
				ATLTRACE(strError);
			}
		}
	}

	return bResult;
}

void GetAuthFile(CString& strFile)
{
	TPTools::GetModulePath(strFile.GetBuffer(MAX_PATH + 1), MAX_PATH, NULL);

	strFile.ReleaseBuffer();
	strFile += lpszAuthFile;
}

template<class T>
bool SimpleStreamWrite(std::ofstream& file, const T* pT)
{
	file.write(reinterpret_cast<const char*>(pT), sizeof(T));

	return !(file.fail());
}

template<class T>
int SimpleStreamRead(std::ifstream& file, T* pT)
{
	file.read(reinterpret_cast<char*>(pT), sizeof(T));

	return file.gcount();
}

const int BUF_LEN = 512;

void Save1Key(std::ofstream& file, KEYAUTH& keyAuth, CRijndael* pCrypt)
{
	SimpleStreamWrite(file, &(keyAuth.dwCount));

	char chData[BUF_LEN], chCrypt[BUF_LEN];
	ZeroMemory(chData, BUF_LEN);
	ZeroMemory(chCrypt, BUF_LEN);

	::memcpy_s(chData, BUF_LEN,
			   (LPCTSTR)keyAuth.strKey,
			   keyAuth.strKey.GetLength() * sizeof(TCHAR));
	pCrypt->Encrypt(chData, chCrypt, BUF_LEN);

	file.write(chCrypt, BUF_LEN);
}

void Load1Key(std::ifstream& file, KEYAUTH& keyAuth, CRijndael* pCrypt)
{
	SimpleStreamRead(file, &(keyAuth.dwCount));

	char chData[BUF_LEN], chCrypt[BUF_LEN];
	ZeroMemory(chData, BUF_LEN);
	ZeroMemory(chCrypt, BUF_LEN);

	file.read(chCrypt, BUF_LEN);

	pCrypt->Decrypt(chCrypt, chData, BUF_LEN);

	keyAuth.strKey = (LPCTSTR)(chData);
}

BOOL CTPAuthCenter::Save()
{
	BOOL bResult = FALSE;

	try
	{
		CString strFile;
		GetAuthFile(strFile);

		std::ofstream file;
		file.open(strFile, std::ios::out | std::ios::binary);

		DWORD dwCount = m_Authorizations.size();
		::SimpleStreamWrite(file, &dwCount);

		CKeyAuthPtr		pAuth;
		CKeyAuthIter	iter = m_Authorizations.begin();

		for ( ; iter != m_Authorizations.end(); ++iter )
		{
			pAuth = (*iter).second;
			Save1Key(file, *pAuth, m_pCrypt);
		}
	}
	catch (...)
	{}

	return bResult;
}

BOOL CTPAuthCenter::Load()
{
	BOOL bResult = FALSE;

	try
	{
		CString strFile;
		GetAuthFile(strFile);

		std::ifstream file;
		file.open(strFile, std::ios::in | std::ios::binary);

		DWORD dwCount = 0;
		::SimpleStreamRead(file, &dwCount);

		CKeyAuthPtr pAuth;

		for ( DWORD d = 0; d < dwCount; ++d )
		{
			pAuth = new KEYAUTH;
			pAuth->bOpen = FALSE;
			Load1Key(file, *pAuth, m_pCrypt);

			if ( 0 < pAuth->dwCount )
			{
				m_Authorizations.insert(CKeyAuths::value_type(pAuth->strKey, pAuth));
			}
		}
	}
	catch (...)
	{}

	return bResult;
}

void CTPAuthCenter::AdviseSinkCallback(IMsgStore* store,
									   ULONG cNotif,
									   LPNOTIFICATION lpNotifications)
{
	CTPAuthCenter* pInstance = Instance();
	IMsgStore* pMsgStore = CMAPICenter::GetSMSStore();

	if ( store == pMsgStore )
	{
		if ( 0 < cNotif && NULL != lpNotifications )
		{
			for ( ULONG ul = 0; ul < cNotif; ++ul )
			{
				NOTIFICATION& rNotify = lpNotifications[ul];

				if ( MAPI_MESSAGE == rNotify.info.obj.ulObjType )
				{
					switch (rNotify.ulEventType)
					{
					case fnevObjectCreated:
						{
							::Sleep(1500);
							IMessage* pMessage = NULL;
							::IMsgStoreGetMessage(pMsgStore,
												  rNotify.info.newmail.cbEntryID,
												  rNotify.info.newmail.lpEntryID,
												  ((IUnknown**)(&pMessage)));

							LPSPropValue prop = NULL;
							::IMessageGetProperty(pMessage, PR_SUBJECT, &prop);
							CString strSubject(prop->Value.lpszW);

							CKeyAuths::iterator iter = pInstance->m_Authorizations.find(strSubject);

							if ( pInstance->m_Authorizations.end() != iter )
							{
								CKeyAuthPtr pKeyAuth = (*iter).second;

								::IMessageGetProperty(pMessage, PR_SENDER_EMAIL_ADDRESS, &prop);
								CString strSender(prop->Value.lpszW);

								if ( strSender.CompareNoCase(pKeyAuth->strCode) )
								{
									::IMessageSetProperty(pMessage, PR_MESSAGE_FLAGS, MSGFLAG_READ);

									pKeyAuth->dwCount += uiAddAuthCounts;

									if ( pInstance->m_pAuthDlg->IsWindow() )
									{
										pInstance->m_pAuthDlg->EndDialog(-1);
									}
								}
							}

							pMessage->Release();
						}
						break;

					default:
						break;
					}
				}
			}
		}
	}
}
